#include "stdio.h"
#include "stdlib.h"
#include "assert.h"
#include "kern_ll.h"

// taken from OS 2 class
/*
	kern_ll.c
		linked with kern_ll.h



*/



/*	Arguments: PLINKEDLIST ptrOject, PLINKEDLIST ptrLinkedListEntry	
 * 	Description: ptrListEntry will usually be the head. ptrLinkedListEntry will be inserted
 *  	after ptrListEntry, unless ptrListEntry is null, in which case ptrLinkedListEntry
 * 		will be returned
 * 	Returns:  pointer to ptrLinkedListEntry, which has been modified
 */
void KernAddListEntry(PLINKEDLIST *ptrListEntry,PLINKEDLIST ptrLinkedListEntry)
{
	if (!(*ptrListEntry))
		ptrLinkedListEntry->nextPtr = ptrLinkedListEntry->previousPtr = NULL;
	else
	{
		ptrLinkedListEntry->nextPtr = *ptrListEntry;
		ptrLinkedListEntry->previousPtr = (*ptrListEntry)->previousPtr;
		(*ptrListEntry)->previousPtr = ptrLinkedListEntry;
	}
	*ptrListEntry = ptrLinkedListEntry;
}

/*	Arguments: PLINKEDLIST ptrListEntry, PLINKEDLIST ptrLocation, PLINKEDLIST ptrLinkedListEntry
 * 	Description: inserts ptrLinkedListEntry after ptrLocation. If ptrLocation is null
 * 		then ptrlinkedListEntry is inserted after ptrListEntry, assuming it is not null
 * 	Returns:  Nothing
 */
void KernAddListEntryAfter(PLINKEDLIST *ptrListEntry, PLINKEDLIST ptrLocation, PLINKEDLIST ptrLinkedListEntry)
{
	
	// assume that ptrListEntry and ptrLocation are not null
	assert( *ptrListEntry != NULL );
	
	// if ptrLocation is NULL, then we insert afer ptrListEntry
	// which results in the same effect as calling KernAddListEntry
	if (ptrLocation == NULL)
		ptrLocation = *ptrListEntry;	
	
	
	// set the next ptr for ptrLocation to our 
	KernAddListEntry(&(ptrLocation->nextPtr),ptrLinkedListEntry);
	ptrLinkedListEntry->previousPtr = ptrLocation;
	
		
		
}

/*	Arguments: PLINKEDLIST ptrListEntry, PLINKEDLIST  ptrListEntrysRemoveList
 * 	Description: Unlinks ll ListEntry at ptrListEntrysRemoveList
 * 	Returns:  Nothing
 */
void KernUnlinkListEntry(PLINKEDLIST *ptrListEntry, PLINKEDLIST  ptrListEntrysRemoveList)
{
  /* Make the "next pointer" of the previous node point to the node following
pllRem */
  if (ptrListEntrysRemoveList->previousPtr != NULL)
    ptrListEntrysRemoveList->previousPtr->nextPtr = ptrListEntrysRemoveList->nextPtr;
  else
    /* If pllRem's "previous" is null then pllRem is at the head of the list,
which must be adjusted */
    (*ptrListEntry) = ptrListEntrysRemoveList->nextPtr;
  /* Make the "previous pointer" of the next node point to the node preceding
pllRem */
  if (ptrListEntrysRemoveList->nextPtr != NULL)
    ptrListEntrysRemoveList->nextPtr->previousPtr = ptrListEntrysRemoveList->previousPtr;
  
}


void KernMoveListPtr(PLINKEDLIST *ptrListEntryFrom, PLINKEDLIST *ptrListEntryTo, PLINKEDLIST startPtr, PLINKEDLIST endPtr )
{
	PLINKEDLIST previous_ptr = startPtr->previousPtr,next_ptr = endPtr->nextPtr;
	
	// assume that ptrListEntry and ptrLocation are not null
	assert( *ptrListEntryFrom != NULL );	
	
	if (startPtr->previousPtr == NULL && endPtr->nextPtr == NULL)
		*ptrListEntryFrom = NULL;
		
		
	if (previous_ptr != NULL) // at the beginning of list
	{
		previous_ptr->nextPtr = next_ptr;	
	}
	if (next_ptr != NULL)
	{
		
		next_ptr->previousPtr=previous_ptr;
	}
	
	endPtr->nextPtr = *ptrListEntryTo;
	if (*ptrListEntryTo != NULL)
		(*ptrListEntryTo)->previousPtr = endPtr;
	startPtr->previousPtr = NULL;
	*ptrListEntryTo = startPtr;
	*ptrListEntryFrom = next_ptr;
	
}

